/**
 * LinkedLST
 * May 11, 2011
 * LocationsView.java - Displays a list of locations
 * a courier needs to visit, sorted by "Unvisited" and
 * "Visited"
 */

package edu.washington.cs.labspecimentransport;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.conn.ConnectTimeoutException;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import edu.washington.cs.labspecimentransport.adapters.SeparatedListAdapter;
import edu.washington.cs.labspecimentransport.data.DataQuery;
import edu.washington.cs.labspecimentransport.dataobjects.Location;
import edu.washington.cs.labspecimentransport.dataobjects.StopInstance;
import edu.washington.cs.labspecimentransport.ops.CommonHandlers;
import edu.washington.cs.labspecimentransport.ops.Keys;

/**
 * A LocationsView displays a list of locations that a courier needs to visit. 
 * Locations are sorted by "Unvisited" and "Visited".
 * 
 * <p>
 * An intent with the following keys are expected:
 * 	int : KEY_COURIERID - the courier id
 *
 */
public class LocationsView extends Activity {
	
	private int courierId;				// the id of the courier logged in
	private DataQuery dq;				// pointer to interned DataQuery
	private Bundle courierInfoBundle;	// pointer to intent bundle
	
	// list of visited and unvisited stops
	private List<StopInstance> visitedLocations;
	private List<StopInstance> unvisitedLocations;
	
	// list of locations associated with visited and unvisited stops
	private List<Location> unvisitedLocationObjects;
	private List<Location> visitedLocationObjects;
	
	// flag for whether or not initialization of activity has occured
	private boolean firstExecution;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.locations);
        firstExecution = true;
        
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 
        
        setupButtons(); 			// setup the header buttons
        updateLocations(false); 	// update the list of locations
    }
    
    /**
     * Define the options menu.
     */
    public boolean onCreateOptionsMenu(Menu menu) {
    	menu.add(0, Keys.MENUID_REFRESH, 0, R.string.option_refresh);
    	menu.add(0, Keys.MENUID_HOME, 0, R.string.option_home);
    	menu.add(0, Keys.MENUID_HELP, 0, R.string.option_help);
    	return true;
    }

    /**
     * Define functionality for each item in options menu.
     */
    public boolean onOptionsItemSelected(MenuItem item) {   
        switch(item.getItemId()) {
        case Keys.MENUID_REFRESH:
        	updateLocations(true);
        	break;
        
        case Keys.MENUID_HOME:
        	CommonHandlers.returnHome(this);
        	break;
        	
        case Keys.MENUID_HELP:
        	CommonHandlers.startHelp(this);
        	break;
        	
        default:
        	super.onOptionsItemSelected(item);
        	break;
        }
        
        return true;
    }
    
    /**
     * Extract information from intent
     */
    private void getPassedData() {
    	courierInfoBundle = getIntent().getExtras();
    	courierId = courierInfoBundle.getInt(Keys.KEY_COURIERID);
    	dq = DataQuery.getInstance();
    }    
    
    /**
     * Adds listeners to the top header buttons (home and refresh)
     */
    private void setupButtons() {
    	// onClick listener for "Home" button
    	Button h = (Button) findViewById(R.id.home_button);
    	h.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				CommonHandlers.returnHome(LocationsView.this);
			}
    	}); 
    	
    	// onClick listener for "Refresh" button
    	Button r = (Button) findViewById(R.id.refresh_button);
    	r.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				updateLocations(true);
			}
    	});   	
    }
    
    /**
     * Updates the list of locations
     * @param flushCache set to true if cache needs to be updated
     */
    public void updateLocations(boolean flushCache) {
    	if (flushCache) {
    		dq.flushEntireCache();
    	}
    	new UpdateLocations().execute();	
    }
    
    /**
     * Displays the list of locations onto the screen
     */
    private void displayList() {
    	// display error toast if query failed
    	if (visitedLocations == null || unvisitedLocations == null) {
    		Toast toast = Toast.makeText(this, 
    				R.string.error_default, Toast.LENGTH_LONG);
    		toast.show();
    		
    	// otherwise set the adapter for list of locations
    	} else {
	        SeparatedListAdapter adapter = new SeparatedListAdapter(this);
	        adapter.addSection("Unvisited (" + unvisitedLocations.size() + " locations)", 
	        		new LocationsViewAdapter(this, unvisitedLocations, unvisitedLocationObjects));
	        adapter.addSection("Visited (" + visitedLocations.size() + " locations)", 
	        		new LocationsViewAdapter(this, visitedLocations, visitedLocationObjects));
	        
	        ListView lv = (ListView) findViewById(R.id.listOfLocations);
	        lv.setAdapter(adapter);
	        
	        // when a location is clicked, open up ClientView for that location
	        lv.setOnItemClickListener(new OnItemClickListener() {
				public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
					StopInstance l = (StopInstance) parent.getAdapter().getItem(position);
					
					TextView tv = (TextView) view.findViewById(R.id.location_name);
					
					Intent i = new Intent(LocationsView.this, ClientView.class);
					Bundle b = new Bundle();
					b.putAll(LocationsView.this.getIntent().getExtras());
					b.putInt(Keys.KEY_COURIERID, courierId);
					b.putInt(Keys.KEY_LOCATIONID, l.getLocation_id());			
					b.putString(Keys.KEY_LOCATIONNAME, tv.getText().toString());
					i.putExtras(b);
					
					startActivity(i);
				}
	        });
    	}
    }
    
    /**
     * Adapter for displaying list of locations.
     */
    private class LocationsViewAdapter extends BaseAdapter {
    	private Context ctx;
    	private List<StopInstance> locationsList;
    	private List<Location> locationObjects;
    	
    	public LocationsViewAdapter(Context ctx, 
    			List<StopInstance> locationsList, List<Location> locationObjects) {
    		this.ctx = ctx;
    		this.locationsList = locationsList;
    		this.locationObjects = locationObjects;
    	}
    	
		public int getCount() {
			return locationsList.size();
		}

		public StopInstance getItem(int position) {
			return locationsList.get(position);
		}

		public long getItemId(int position) {
			return locationsList.indexOf(this.getItem(position));
		}

		public View getView(int position, View view, ViewGroup parent) {
			LinearLayout itemLayout = (LinearLayout) 
				LayoutInflater.from(ctx).inflate(R.layout.locations_single, parent, false);
			
			Location loc = locationObjects.get(position);
			
			TextView locationName = (TextView) itemLayout.findViewById(R.id.location_name);
			locationName.setText(loc.getName());
			
			return itemLayout;
		}		
    }
    
    /**
     * Service to get locations from the backend database
     */
	private class UpdateLocations extends AsyncTask<Void, Void, Void> {
		private ProgressDialog dialog;
		private boolean success;
		private boolean timeout;
		
		// before execution
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			dialog = ProgressDialog.show(LocationsView.this, "", 
					getString(R.string.location_load), true, true,
					new DialogInterface.OnCancelListener(){
				public void onCancel(DialogInterface dialog) {
					UpdateLocations.this.cancel(true);
					finish();
				}
			});
			success = true;
			timeout = false;
		}
		
		// execution
		@Override
		protected Void doInBackground(Void... v) {
			if (firstExecution) {
				getPassedData();
				firstExecution = false;
			}
			try {
				visitedLocationObjects = new ArrayList<Location>();
				unvisitedLocationObjects = new ArrayList<Location>();
				
				// get unvisited stops and their corresponding locations
				unvisitedLocations = dq.getUnvisitedLocationsByCourierId(courierId);
				for (StopInstance s : unvisitedLocations) {
					Location loc = dq.getLocationOfStopInstance(s);
					unvisitedLocationObjects.add(loc);
				}

				// get visited stops and their corresponding locations
				visitedLocations = dq.getVisitedLocationsByCourierId(courierId);
				for (StopInstance s : visitedLocations) {
					Location loc = dq.getLocationOfStopInstance(s);
					visitedLocationObjects.add(loc);
				}
			} catch (NullPointerException e) {
				success = false;
				e.printStackTrace();
			} catch (ConnectTimeoutException e) {
				timeout = true;
			}
			return null;
		}

		// after execution
		@Override
		protected void onPostExecute(Void unused) {
			dialog.dismiss();
			if (success) {
				displayList();
			} else if (timeout) {
	    		Toast toast = Toast.makeText(LocationsView.this, 
	    				R.string.error_timeout, Toast.LENGTH_LONG);
	    		toast.show();
			} else {
	    		Toast toast = Toast.makeText(LocationsView.this, 
	    				R.string.error_default, Toast.LENGTH_LONG);
	    		toast.show();
			}
		}
	}    
}